Fix the "hda lost interrupt" issue when creating a VMX guest on a PAE
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 21 Apr 2006 09:11:00 +0000 (10:11 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 21 Apr 2006 09:11:00 +0000 (10:11 +0100)
host.

Occasionally when injecting an IDE DMA interrupt into the guest, a
page fault occurs (e.g., because the IDT mapping is not present in
shadow pagetables).  This causes an immediate vmexit and, because it
occurred during event delivery, the original VM_ENTRY_INTR_INFO_FIELD
is kept in IDT_VECTORING_INFO_FIELD.

The current code copies IDT_VECTORING_INFO_FIELD back to
VM_ENTRY_INTR_INFO_FIELD, intending that the interrupt will be
injected again on next vmresume.

However, there is a corner case: if, before the next vmresume, a timer
interrupt happened then vmx_intr_assist may overwrite the information
on VM_ENTRY_INTR_INFO_FIELD, and the IDE DMA interrupt is effectively
lost.

This patch checks the IDT_VECTORING_INFO_FIELD in vmx_intr_assist and,
if it is set, copies it to VM_ENTRY_INTR_INFO_FIELD and returns.

Signed-off-by: Yunhong Jiang <Yunhong.jiang@intel.com>
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
xen/arch/x86/hvm/vmx/io.c
xen/arch/x86/hvm/vmx/vmx.c

index 5be8bed9710a8fc358b30c48f4303b38bb78c682..9835445d618e6a840a1a9ee84425bdb10f6cf37f 100644 (file)
@@ -153,6 +153,9 @@ asmlinkage void vmx_intr_assist(void)
     struct hvm_domain *plat=&v->domain->arch.hvm_domain;
     struct hvm_time_info *time_info = &plat->vpit.time_info;
     struct hvm_virpic *pic= &plat->vpic;
+    unsigned int idtv_info_field;
+    unsigned long inst_len;
+    int    has_ext_irq;
 
     if ( v->vcpu_id == 0 )
         hvm_pic_assist(v);
@@ -162,8 +165,29 @@ asmlinkage void vmx_intr_assist(void)
         pic_set_irq(pic, 0, 1);
     }
 
-    if ( !cpu_has_pending_irq(v) ) return;
+    has_ext_irq = cpu_has_pending_irq(v);
+    __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
+    if (idtv_info_field & INTR_INFO_VALID_MASK) {
+        __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
 
+        __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
+        if (inst_len >= 1 && inst_len <= 15)
+            __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
+
+        if (idtv_info_field & 0x800) { /* valid error code */
+            unsigned long error_code;
+            __vmread(IDT_VECTORING_ERROR_CODE, &error_code);
+            __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+        }
+        if ( has_ext_irq )
+            enable_irq_window(v);
+
+        HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
+
+        return;
+    }
+
+    if ( !has_ext_irq ) return;
     if ( is_interruptibility_state() ) {    /* pre-cleared for emulated instruction */
         enable_irq_window(v);
         HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
index 052c11ba2adca7f56c6496ecff2eb14100af8bd9..86e3d9c7632edf142e2a362e4315114123feb111 100644 (file)
@@ -2046,7 +2046,7 @@ void restore_cpu_user_regs(struct cpu_user_regs *regs)
 
 asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
 {
-    unsigned int exit_reason, idtv_info_field;
+    unsigned int exit_reason;
     unsigned long exit_qualification, eip, inst_len = 0;
     struct vcpu *v = current;
     int error;
@@ -2056,23 +2056,6 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
 
     perfc_incra(vmexits, exit_reason);
 
-    __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
-    if (idtv_info_field & INTR_INFO_VALID_MASK) {
-        __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
-
-        __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
-        if (inst_len >= 1 && inst_len <= 15)
-            __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
-
-        if (idtv_info_field & 0x800) { /* valid error code */
-            unsigned long error_code;
-            __vmread(IDT_VECTORING_ERROR_CODE, &error_code);
-            __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
-        }
-
-        HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
-    }
-
     /* don't bother H/W interrutps */
     if (exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT &&
         exit_reason != EXIT_REASON_VMCALL &&